﻿#pragma once

#include "precomp.h"
#include "bullet.h"
#include "enemy.h"
#include "effect.h"
#include "renders.h"
#include "sound.h"
#include "dialog.h"
#include "player.h"
#include "global_state.h"
//#include "bulletmlparser.h"
//#include "bulletmlparser-tinyxml.h"
//#include "bulletmlrunner.h"
//
//#pragma comment(lib, "bulletml.lib")

class Bullet;
class Effect;
class Enemy;
class EnemyBoss;
class Spellcard_Work;
struct Pattern;

// ==================  Эксперименты с BulletML =======================
//class BulletCommand : public BulletMLRunner {
//public:
//	// ...
//	BulletCommand(BulletMLParser* bp, Bullet* b);
//	BulletCommand(BulletMLState* bs, Bullet* b);
//	~BulletCommand();
//	// ...
//	virtual void doVanish();
//	virtual void createSimpleBullet(double direction, double speed);
//	virtual void createBullet(BulletMLState* state, double direction, double speed);
//	virtual void doChangeDirection(double direction);
//	virtual void doChangeSpeed(double speed);
//	virtual void doAccelX(double accel);
//	virtual void doAccelY(double accel);
//	virtual double getBulletSpeedX();
//	virtual double getBulletSpeedY();
//	virtual double getBulletDirection();
//	virtual double getAimDirection();
//	virtual double getBulletSpeed();
//	virtual double getDefaultSpeed();
//
//	virtual double getRank();
//	virtual int getTurn();
//	virtual int getEndTurn();
//
//public:
//	// the bullet you will handle
//	Bullet* bullet_;
//	Pattern* pattern_;
//};

// ==========================================================

class Behaviour {
public:
    Behaviour();
    virtual ~Behaviour();
    virtual bool Update(Bullet *p_bullet, float time)=0; // returns false to destroy a bullet
public:
	bool InsideScreen(CL_Vec2<float> position);
	bool InsideScreen(float pos_x, float pos_y);
	CL_Rectf visible_rect;
};

class Effect_Behaviour {
public:
    Effect_Behaviour();
    virtual ~Effect_Behaviour();
    virtual bool Update(Effect *p_effect, float time)=0; // returns false to destroy
public:
	CL_Rectf visible_rect;
};

class Enemy_Path {
public:
    Enemy_Path();
    virtual ~Enemy_Path();
    virtual int Update(Enemy *p_enemy, float time)=0; // возвращает статус: 0 - унчтожен, 1 - живой, 2 - анимация уничтожения
public:
	bool InsideScreen(CL_Rectf position);
	bool InsideScreen(CL_Vec2<float> position);
	bool InsideScreen(float pos_x, float pos_y);
	CL_Rectf visible_rect;
};

// Объект запуска паттерна пуль
struct Pattern{
	char active;
	int type;
	unsigned int fired;
	float time_working;
	float sound_time;

	// ================ для BulletML =======================
	//Bullet* pbullet;
	//BulletCommand* bc;
	//int cur_turn;
	// ===============================================

	int active_bullets; // количество активных пуль
	int trigger; // для разных целей

	// Параметризация пуль паттерна
	float bullet_speed;
	int bullet_number;
	Behaviour* bullet_behaviour;
	float bullet_time1;
	float bullet_time2;
	float bullet_param1;
	float bullet_start_param1;
	float pattern_speed;
	float pattern_param1;
	float pattern_param2;
	float pattern_param3;
	float pattern_param4;
	float pattern_param5;
	CL_String bullet_effect;
	int bullet_effect_index;

	float work_param1;
	float work_param2;
	float work_param3;
	float work_param4;

	CL_Vec2<float> start_position;
	Enemy* enemy_object;
	int id;
};

// Менеджер траекторий пуль, врагов и паттернов выпуска пуль
// Спеллкарт?
class PatternManager{
public:
	PatternManager();
	~PatternManager();
	void Init(CL_Rectf rect);
	Behaviour* GetBulletBehaviour(CL_String name);
	Enemy_Path* GetEnemyPath(CL_String name);
	Effect_Behaviour* GetEffectBehaviour(CL_String name);
	Spellcard_Work* GetSpellcard(CL_String name);

	void Update(float time);
	void Clear();
	void Load(CL_ResourceManager &resources, CL_VirtualDirectory &vdir);
	void LaunchPattern(CL_Vec2<float> from_position, int type, Enemy*  l_enemy);
	void CreateEffect(CL_String name, CL_Vec2<float> pos, int index);

	Bullet GetBulletTemplate(Pattern &pat, CL_Vec2f pos);
	Bullet GetBulletTemplateByName(CL_String bname);
	CL_Vec2f get_direction_to_player(CL_Vec2f from_where);
	CL_Angle get_bullet_orientation(CL_Vec2f);
	CL_Vec2f get_move_position1(CL_Vec2f start_pos, CL_Vec2f end_pos, float v, float a, float t); // рассчёт движения с плавным началом и концом, со скоростью и ускорением
	CL_Vec2f get_move_position2(CL_Vec2f start_pos, CL_Vec2f end_pos, float time_to_move, float slowdown, float t); // рассчёт движения с плавным началом и концом, slowdown - на каком участке делать замедление, в долях (0.1 и т.д.)

	// BulletML
	//BulletMLParser* bmlparser;
private:
	std::map<std::string, Behaviour*> bullet_behaviours;
	std::map<std::string, Enemy_Path*> enemy_paths;
	std::map<std::string, Effect_Behaviour*> effect_behaviours;
	std::map<std::string, Bullet> bullet_templates;
	std::map<std::string, Pattern> pattern_templates;
	std::vector<CL_SharedPtr<Pattern>> _patterns;
	std::map<std::string, Spellcard_Work*> spellcards;

	float player_shot_sound_time;
	int pcount;
};

extern PatternManager patterns;

// ===============================================
// =                 Траектории пуль
// ===============================================

class Behaviour_Simple : public Behaviour {
public:
	Behaviour_Simple(CL_Rectf clipping_rect);
	virtual bool Update(Bullet *p_bullet, float time);
};

class Behaviour_Simple2 : public Behaviour {
public:
	Behaviour_Simple2(CL_Rectf clipping_rect, float d_time);
	virtual bool Update(Bullet *p_bullet, float time);
private:
	float dtime;
};

class Behaviour_Simple3 : public Behaviour {
public:
	Behaviour_Simple3(CL_Rectf clipping_rect, float d_accel, float t_speed);
	virtual bool Update(Bullet *p_bullet, float time);
private:
	float daccel;
	float topspeed;
};

class Behaviour_Timed : public Behaviour {
public:
	Behaviour_Timed(CL_Rectf clipping_rect);
	virtual bool Update(Bullet *p_bullet, float time);
private:
	float dtime;
};

class Behaviour_Stopping : public Behaviour {
public:
	Behaviour_Stopping(CL_Rectf clipping_rect);
	virtual bool Update(Bullet *p_bullet, float time);
private:
	float dtime;
};

class Behaviour_Turning : public Behaviour {
public:
	Behaviour_Turning(CL_Rectf clipping_rect);
	virtual bool Update(Bullet *p_bullet, float time);
private:
};

// Движется по дуге с подкруткой, в декартовых координатах
class Behaviour_Arc : public Behaviour {
public:
	Behaviour_Arc(CL_Rectf clipping_rect, float d_time, float d_speed);
	virtual bool Update(Bullet *p_bullet, float time);
private:
	float dtime; // время, через которое менять скорость
	float dspeed; // коэффициент смены скорости
};

// Движется по дуге с подкруткой, в декартовых координатах, через некоторое время переходя в касательную
class Behaviour_Arc_Line : public Behaviour {
public:
	Behaviour_Arc_Line(CL_Rectf clipping_rect, float d_time, float d_speed);
	virtual bool Update(Bullet *p_bullet, float time);
private:
	float dtime; // время, через которое выводить пулю на касательную
	float dspeed; // коэффициент смены скорости после вывода
};

// Движется по спирали в полярных координатах
class Behaviour_Arc_Polar : public Behaviour {
public:
	Behaviour_Arc_Polar(CL_Rectf clipping_rect, float d_time, float d_speed);
	virtual bool Update(Bullet *p_bullet, float time);
private:
	float dtime; // время, через которое менять скорость
	float dspeed; // коэффициент смены скорости
};

// Спеллкарта "Перекрестье", наводимые пули
class Behaviour_Player_Bullet1 : public Behaviour {
public:
	Behaviour_Player_Bullet1(CL_Rectf clipping_rect, float _radius, float d_angle, float d_speed);
	virtual bool Update(Bullet *p_bullet, float time);
private:
	float dangle; // через какое угловое расстояние выходить на касательную
	float dspeed; // коэффициент смены скорости
	float radius; // на какую окружность выходить
};

class Behaviour_Player_Bullet2 : public Behaviour {
public:
	Behaviour_Player_Bullet2(CL_Rectf clipping_rect, float d_angle, float d_speed);
	virtual bool Update(Bullet *p_bullet, float time);
private:
	float dangle; // через какое угловое расстояние выходить на касательную
	float dspeed; // коэффициент смены скорости
};

// Крутящаяся после сдувания пуля
class Behaviour_Spinning : public Behaviour {
public:
	Behaviour_Spinning(CL_Rectf clipping_rect);
	virtual bool Update(Bullet *p_bullet, float time);
};

// ============   Контролируемые паттернами =====================

// Движется определённое время, после чего останавливается.
// По триггеру паттерна изменяет скорость и направление
class Behaviour_Controlled1 : public Behaviour {
public:
	Behaviour_Controlled1(CL_Rectf clipping_rect);
	virtual bool Update(Bullet *p_bullet, float time);
};


// ============   Лазоры   =====================

class Behaviour_Lazor : public Behaviour {
public:
	Behaviour_Lazor();
	virtual bool Update(Bullet *p_bullet, float time);
};


// ===============================================
// =                    Траектории врагов
// ===============================================

class Enemy_Path_Straight : public Enemy_Path {
public:
	Enemy_Path_Straight(CL_Rectf clipping_rect);
	virtual int Update(Enemy *p_enemy, float time);
};

class Enemy_Path_Move_Aside : public Enemy_Path {
public:
	Enemy_Path_Move_Aside(CL_Rectf clipping_rect, float pscreen, bool orientation);
	virtual int Update(Enemy *p_enemy, float time);
private:
	float y;
	bool left;
};

class Enemy_Path_Stop_Wait_Move : public Enemy_Path {
public:
	Enemy_Path_Stop_Wait_Move(CL_Rectf clipping_rect, float wtime);
	virtual int Update(Enemy *p_enemy, float time);
private:
	float wait_time;
};

class Enemy_Path_Go_Wait_Go : public Enemy_Path {
public:
	Enemy_Path_Go_Wait_Go(CL_Rectf clipping_rect, float wtime);
	virtual int Update(Enemy *p_enemy, float time);
private:
	float wait_time;
};

class Enemy_Path_One_Point_Stop : public Enemy_Path {
public:
	Enemy_Path_One_Point_Stop(CL_Rectf clipping_rect, float wtime);
	virtual int Update(Enemy *p_enemy, float time);
private:
	float wait_time;
};

class Enemy_Path_Sinus : public Enemy_Path {
public:
	Enemy_Path_Sinus(float s);
	virtual int Update(Enemy *p_enemy, float time);
private:
	float scale;
};

// ------------------------------------------------------------------------------------------
// -                     Поведение боссов
// ------------------------------------------------------------------------------------------
class Enemy_Path_Boss : public Enemy_Path {
public:
	Enemy_Path_Boss(CL_Rectf clipping_rect, float y);
	virtual int Update(Enemy *p_enemy, float time);
private:
	float h;
};

// ------------------------------------------------------------------------------------------
// -                     Спеллкарты
// ------------------------------------------------------------------------------------------

struct _Spellcard_Action{
	int type; // 0 - move; 1 - wait; 2 - pattern; 3 - speed
	int x;
	int y;
};

struct _Spellcard_Effect{
	int type; // 0 - ring; 1 - mahoujin; 2 - background; 3 - particle
	int param_int;
	float param1;
	float param2;
	float param3;
};

class Spellcard_Work {
public:
    Spellcard_Work(CL_ResourceManager &resources, CL_String name);
    ~Spellcard_Work();
    int Update(EnemyBoss *b_enemy, float time); // возвращает статус: 0 - спеллкарта работает, 1 - завершена
	void PushSpellActions(CL_ResourceManager &resources, CL_String name);
public:
	int spellcard_time;
	std::vector<_Spellcard_Action> spellcard_actions;
	std::vector<_Spellcard_Effect> spellcard_effects;
};


// ===============================================
// =                    Эффекты
// ===============================================
class Effect_Behaviour_Stay_Still : public Effect_Behaviour {
public:
	Effect_Behaviour_Stay_Still();
	virtual bool Update(Effect *p_effect, float time);
};

class Effect_Behaviour_Score_Float : public Effect_Behaviour {
public:
	Effect_Behaviour_Score_Float();
	virtual bool Update(Effect *p_effect, float time);
};

class Effect_Behaviour_Flyoff : public Effect_Behaviour {
public:
	Effect_Behaviour_Flyoff();
	virtual bool Update(Effect *p_effect, float time);
};

class Effect_Behaviour_Grav : public Effect_Behaviour {
public:
	Effect_Behaviour_Grav(double gr);
	virtual bool Update(Effect *p_effect, float time);
private:
	double g;
};


// Паттерны
// Информация о количестве и запускаемых паттернах хранится в игровых объектах - игроке и врагах.
// Сами паттерны добавляются в отдельный обработчик, который принимает на вход тип и количество, и выпускающий объект. И какие-то ещё параметры, направленность, например(или это в типе?)
// После этого паттерны обрабатываются отдельно и объект о них уже не заботится.
// Паттерны занимаются тем, что выпускают пули и спецэффекты выстрелов, пока жив родитель, или пока не закончится паттерн.
// Спеллкарты строить на паттернах.
// Паттерны запускаются по трём типам событий - прошедшее время, пройденный путь, и триггер. Запуском заведует отдельная
// процедура стреляющего объекта.


// В типах паттернов заложена основная информация
// Первые три цифры - внешний вид пули, через интервалы по 20(для разных цветов)
// --------------------------
// Вид:
// 0 - 16			- обычные пули врагов с ободом
// 20 - 36			- самые мелкие пульки
//
//
// --------------------------
// Остальные цифры - типы паттернов
// 0 - 999			- пули, летящие прямо в игрока
// 
//
//
//
//
//
//
//
